/****************************************************************************
* This file is part of qtmount, a simple system tray application for mounting and mounting removable media using udisks.
* Copyright (C) 2010 Aleksey Kamenskikh
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>
*
* Contact e-mail: aleksey.kamenskikh@gmail.com
*
****************************************************************************/


#include "tray.h"

Tray::Tray()
{
	createActions();
	createMenu();
	createTrayIcon();

	connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
                this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
  
	mountIcon   = QIcon(QIcon::fromTheme("list-add",QIcon("mount.png")));
	unmountIcon = QIcon(QIcon::fromTheme("list-remove",QIcon("unmount.png")));


	trayIcon->show();

	if (!QDBusConnection::systemBus().isConnected())	
		trayIcon->showMessage(tr("Error"),tr("can't connect to DBus system bus"),QSystemTrayIcon::Critical);
  else
		QDBusConnection::systemBus().connect(UDISKSSERVICE, "/org/freedesktop/UDisks", UDISKSSERVICE, "DeviceAdded" , this, SLOT(deviceAdded(QDBusObjectPath)));
}

void Tray::createTrayIcon()
{
	trayIcon = new QSystemTrayIcon(this);
	trayIcon->setContextMenu(trayMenu);
	trayIcon->setIcon(QIcon::fromTheme("drive-removable-media",QIcon("qtmount.png")));
}

void Tray::createActions()
{
	quitAction = new QAction(tr("&Quit"), this);
	connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
}

void Tray::createMenu()
{
	trayMenu = new QMenu(this);
}

void Tray::iconActivated(QSystemTrayIcon::ActivationReason reason)
{
	if (reason == QSystemTrayIcon::Context)
	{
		trayMenu->clear();
		QDBusInterface udisks_iface(UDISKSSERVICE, "/org/freedesktop/UDisks", UDISKSSERVICE, QDBusConnection::systemBus());
		QDBusReply< QList <QDBusObjectPath> > device_list = udisks_iface.call("EnumerateDevices");
		bool is_partition;
		bool is_internal;
		bool is_mounted;
		QString mounttext;
		QIcon icon;
		QString device_file;
		QString device_label;
		QString device_uuid;
		foreach (QDBusObjectPath device_path, device_list.value())
		{
			is_internal = getUdisksDeviceProperty(device_path.path(), "DeviceIsSystemInternal").toBool();
			is_partition = getUdisksDeviceProperty(device_path.path(), "DeviceIsPartition").toBool();
			is_mounted = getUdisksDeviceProperty(device_path.path(), "DeviceIsMounted").toBool();
			device_file = getUdisksDeviceProperty(device_path.path(), "DeviceFile").toString();
			device_label = getUdisksDeviceProperty(device_path.path(), "IdLabel").toString();
			device_uuid = getUdisksDeviceProperty(device_path.path(), "IdUuid").toString();			
			
			if (is_partition && !is_internal)
			{
				if (!is_mounted)
				{
					icon = mountIcon;
					mounttext = tr("&Mount")+" ";
				}	
				else
				{
					icon = unmountIcon;
					mounttext = tr("&Unmount")+" ";
				}
				if (device_label != "")
					mounttext += device_label;
				else
					mounttext += device_uuid;
				mounttext += " ("+device_file+")";
				
				QAction *action = new QAction(icon, mounttext,this);
				action->setData(device_path.path());
				connect(action, SIGNAL(triggered()), this, SLOT(itemClicked()));
				trayMenu->addAction(action);
			}
		}
		trayMenu->addSeparator();
		trayMenu->addAction(quitAction);
	}
	else
	if (reason == QSystemTrayIcon::MiddleClick)
	{
//		trayIcon->showMessage("Debug",QIcon::themeName());
		;
	}
}

void Tray::itemClicked()
{
	QAction* action = qobject_cast<QAction*>(sender());
	if (action)
	{
		QString devicepath=action->data().toString();
		if (!getUdisksDeviceProperty(devicepath, "DeviceIsMounted").toBool())
		{
			mountDevice(devicepath);
		}
		else
		{
			unmountDevice(devicepath);
		}
	}
}

QVariant Tray::getUdisksDeviceProperty(QString devicepath, QString parametername)
{
	QDBusInterface udisks_property(UDISKSSERVICE,devicepath,"org.freedesktop.DBus.Properties",QDBusConnection::systemBus());
	QDBusReply<QVariant> result = udisks_property.call("Get", "/org/freedesktop/UDisks/Device", parametername);
	return result.value();
}
   
void Tray::mountDevice(QString devicepath)
{
	QDBusInterface udisks_device(UDISKSSERVICE,devicepath,"org.freedesktop.UDisks.Device",QDBusConnection::systemBus());
	QStringList params;
	QList<QVariant> paramv;
	paramv << "" << params;
	udisks_device.callWithCallback("FilesystemMount",paramv,this, SLOT(mountResult(QString)),SLOT(mountError(QDBusError)));
}
   
void Tray::unmountDevice(QString devicepath)
{
  QStringList params;
	QDBusInterface udisks_device(UDISKSSERVICE,devicepath,"org.freedesktop.UDisks.Device",QDBusConnection::systemBus());
	QList <QVariant> paramv;
	paramv << params;
	udisks_device.callWithCallback("FilesystemUnmount",paramv,this, SLOT(unmountResult()),SLOT(unmountError(QDBusError)));
}

void Tray::mountError(QDBusError error)
{
	qDebug() << "Mount failed" << error.message();
	trayIcon -> showMessage(tr("Failed to mount"),udisksErrorToMessage(error.name()),QSystemTrayIcon::Warning);
}

void Tray::mountResult(QString mountPath)
{
	qDebug() << "Mounted to " << mountPath;
	trayIcon -> showMessage(tr("Success"),tr("Mounted successfully to ")+mountPath);
}

void Tray::unmountError(QDBusError error)
{
	qDebug() << "Unmount error " << error.message();
	trayIcon -> showMessage(tr("Failed to unmount"),udisksErrorToMessage(error.name()),QSystemTrayIcon::Warning);
}

void Tray::unmountResult()
{
	qDebug() << "Unmounted successfully";
	trayIcon -> showMessage(tr("Success"),tr("Unmounted successfully"));
}

QString Tray::udisksErrorToMessage(QString errorName)
{
	QString errorMessage;
	if (errorName == "org.freedesktop.UDisks.Error.Busy")
		errorMessage = tr("Device is busy");
	else
	if (errorName == "org.freedesktop.PolicyKit.Error.NotAuthorized")
		errorMessage = tr("Not authorized");
	else
	if (errorName == "org.freedesktop.UDisks.Error.Failed")
		errorMessage = tr("Operation failed");
	else	
	if (errorName == "org.freedesktop.UDisks.Error.FilesystemDriverMissing")
		errorMessage = tr("Filesystem driver missing");
	else
	if (errorName == "org.freedesktop.UDisks.Error.Cancelled")
		errorMessage = tr("Operation cancelled");
	else
		errorMessage = tr("Unexpectable error: ")+errorName;
	return errorMessage;
}

void Tray::deviceAdded(QDBusObjectPath devicePath)
{
	qDebug() << "Added device " << devicePath.path();
  if (getUdisksDeviceProperty(devicePath.path(), "DeviceIsPartition").toBool())
	{
		QString deviceTitle;
		if ((deviceTitle = getUdisksDeviceProperty(devicePath.path(), "IdLabel").toString()) == "")
			deviceTitle = getUdisksDeviceProperty(devicePath.path(), "IdUuid").toString();
		
		trayIcon->showMessage(tr("New media inserted"),deviceTitle+tr(" added"));
	}
}
